#include <QtCore/QFile>
#include <QtCore/QMetaObject>
#include <QtCore/QSettings>
#include <QtGui/QApplication>
#include <QtGui/QGraphicsRectItem>
#include <QyGLInputController.h>
#include <QyDebug.h>
#include <QpwPackages.h>
#include <QpwDecorationObject.h>
#include <QyTexturePool.h>
#include "QpwClient.h"
#include "QpwPlayerController.h"
#include "QpwRenderItems.h"

/**************************************************************************************************/

QpwClient::QpwClient( QObject * parent )
    : QObject(parent),
    rootDir( qApp->applicationDirPath() + "/../data" ),
    client(this),
    playerController(0)
{

    QyTexturePool::staticPool()->glWidget = viewWidget.glWidget();
    viewWidget.setScene(&render);
    readConfig();
    timerId = startTimer(200);
    ( new QyGL::BasicCamViewController(&render) )->setEnabled(true);
    viewWidget.show();
    createMenu();
    client.setObjectName("client");
    QMetaObject::connectSlotsByName(this);

    menuBar.resize( qRound( render.width() ), 18 );

    render.addWidget(&loginDialog)->setPos( 100, 100 );
    loginDialog.close();

}

QpwClient::~QpwClient() {
}

void QpwClient::on_actionNewGame_triggered() {
}

void QpwClient::on_actionJoinGame_triggered() {

    if ( loginDialog.exec() == QDialog::Accepted ) {

        client.login( loginDialog.host(), port, loginDialog.username(),
            loginDialog.passwordHash() );

    }

}

void QpwClient::on_actionQuit_triggered() {

    qApp->quit();

}

void QpwClient::on_client_datagramReceived( QyNet::AbstractDatagramEncoder * datagram ) {

    if ( datagram->type() == QpwNetwork::VariantDatagramType ) {

        QpwNetwork::VariantDatagram * variant = (QpwNetwork::VariantDatagram *) (datagram);
        QUuid uuid;

        switch (variant->dataType) {

        case QpwPackages::PosChangePackage:

            uuid = variant->data[0].toString();

            if ( items.contains(uuid) ) {

                QpwItems::Decoration * item = items[uuid];

                item->position = variant->data[1].toPointF();
                item->rotation = QyMath::degress( variant->data[2].toDouble() );

                if ( playerController->player == item ) {

                    render.setCamPos( -item->position.toPointF() );

                }
//                 QyDbgValue(items[uuid]->position.x());
//                 QyDbgValue(items[uuid]->position.y());

            }
//             else
//                 qWarning( "QpwClient: Received unknow object uuid %s", qPrintable( uuid.toString() ) );

            break;

        case QpwPackages::MakeObjectPackage:
            {

                uuid = variant->data[0].toString();
                QpwItems::Decoration * decoration = addObject( uuid, variant->data[1].toString() );

                if ( uuid == client.uuid() ) {

                    playerController = new QpwPlayerController(&render);
                    playerController->client = &client;
                    playerController->player = decoration;

                }

            }

            break;

        case QpwPackages::DestroyObjectPackage:
            uuid = variant->data[0].toString();

            if ( items.contains(uuid) ) {

                delete items[uuid];
                items.remove(uuid);
                qDebug( "QpwClient: Destroy object %s", qPrintable( uuid.toString() ) );

            }
            break;

        }

    }

}

bool QpwClient::readConfig() {

    QSettings settings( rootDir + "/client.ini", QSettings::IniFormat );

    dataDirPath = rootDir + "/" + settings.value("client/datadir").toString();
    port = settings.value("client/port").toUInt();

    QString styleFilePath = rootDir + "/" + settings.value("client/style").toString();
    if ( QFile::exists(styleFilePath) ) {

        QFile file(styleFilePath);

        if ( file.open(QIODevice::ReadOnly) ) {

            qApp->setStyleSheet( file.readAll() );
            file.close();

        }

    }

    bool ok = true;

    ok = ok && render.loadData(dataDirPath);
    ok = ok && geometryDatabase.load( dataDirPath + "/geometrys.xml" );
    ok = ok && styleDatabase.load( dataDirPath + "/styles.xml" );
    ok = ok && subTypeDatabase.load( dataDirPath + "/subtypes.xml" );

    return ok;
}

bool QpwClient::startGame() {

    bool ok = true;

    render.addWidget(&menuBar);

    return ok;
}

void QpwClient::createMenu() {

    menuBar.addAction( tr("New game"), this, SLOT( on_actionNewGame_triggered() ) )->setObjectName("actionNewGame");
    menuBar.addAction( tr("Join game"), this, SLOT( on_actionJoinGame_triggered() ) )->setObjectName("actionJoinGame");
    menuBar.addAction( tr("Quit"), this, SLOT( on_actionQuit_triggered() ) )->setObjectName("actionQuit");

}

void QpwClient::timerEvent( QTimerEvent * event ) {

    if ( timerId == event->timerId() && render.isInitialized() ) {

        startGame();
        killTimer(timerId);
        timerId = 0;

    }

}

QpwItems::Decoration * QpwClient::addObject( const QUuid & uuid, const QUuid & subTypeUuid ) {

    QpwItems::Decoration * newObject = 0;

    if ( !subTypeDatabase.rows.contains(subTypeUuid) ) {

//         qWarning( "QpwClient: Received unknow subtype uuid %s", qPrintable( subTypeUuid.toString() ) );

        return newObject;
    }

    QpwSubType subType = subTypeDatabase.rows[subTypeUuid];

    switch (subType.baseType) {

    case QpwWorld::DecorationObject::DecorationObjectType:
    case QpwWorld::DecorationObject::QuasiStaticObjectType:
    case QpwWorld::DecorationObject::StaticObjectType:
    case QpwWorld::DecorationObject::DynamicObjectType:
        newObject = new QpwItems::Decoration;
        break;

    }

    if (newObject) {

        newObject->setLayer(&render.layers[subType.objectFunction]);
        newObject->setSubType(subType);

        if ( geometryDatabase.rows.contains(subType.geometryUuid) )
            newObject->setGeometry(geometryDatabase.rows[subType.geometryUuid]);

        if ( styleDatabase.rows.contains(subType.styleUuid) )
            newObject->setStyle(styleDatabase.rows[subType.styleUuid]);

        newObject->uuid = uuid;
        items[uuid] = newObject;

//         qDebug( "QpwClient: Created object %s", qPrintable( uuid.toString() ) );

    }

    return newObject;
}

/**************************************************************************************************/

int main( int argCount, char ** args ) {

    QApplication app( argCount, args );
    QpwClient client;

    return app.exec();
}
